package com.tangsm.spring.boot.api.filter;

import com.tangsm.spring.boot.api.http.BodyReaderRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * http全局过滤器，解决HttpServletResponse body重复读问题
 *
 * @author tangsm
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@WebFilter(filterName = "httpServletRequestWrapperFilter", urlPatterns = {"/*"})
public class HttpServletRequestFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(HttpServletRequestFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper((HttpServletResponse) response);

        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            httpRequest.setCharacterEncoding(StandardCharsets.UTF_8.name());

            String contentType = httpRequest.getContentType();
            // content-type 为 application/json 处理
            if (StringUtils.isNotBlank(contentType) && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                //对于其他的情况，我们统一使用包装类，将请求流进行缓存到容器
                BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper((HttpServletRequest) request);

                log.info("body 请求参数：{}", new String(requestWrapper.getBody()));
                chain.doFilter(requestWrapper, responseWrapper);
            }
            // 其他类型不处理
            else {
                //spring中使用MultipartResolver处理文件上传，所以这里需要将其封装往后传递
                // MultipartResolver resolver = new StandardServletMultipartResolver();
                // MultipartHttpServletRequest servletRequest = resolver.resolveMultipart(httpRequest);

                chain.doFilter(request, response);
            }
        } finally {
            // 读取完Response body之后，通过这个设置回去，就可以使得接口调用者可以正常接收响应了，否则会产生空响应的情况
            // 注意要在过滤器方法的最后调用
            responseWrapper.copyBodyToResponse();
        }
    }

}
